/**
 * @file imagecanvas.cpp
 * @brief 图像画布组件实现文件
 *
 * 实现图像显示、交互绘制和蒙版管理的核心功能
 * 这个文件包含了图像修复系统的可视化逻辑
 */

#include "imagecanvas.h"
#include <QPainter>
#include <QDebug>

/**
 * @brief 构造函数
 * @param parent 父窗口部件
 *
 * 初始化画布的基本属性：
 * - 设置最小尺寸
 * - 启用鼠标跟踪（用于实时绘制）
 */
ImageCanvas::ImageCanvas(QWidget *parent) : QWidget(parent)
{
    setMinimumSize(400, 300);    // 设置画布最小尺寸
    setMouseTracking(true);      // 启用鼠标跟踪，实时获取鼠标位置
}

/**
 * @brief 加载图像文件
 * @param filePath 图像文件路径
 * @return 加载是否成功
 *
 * 加载流程：
 * 1. 使用OpenCV读取图像文件
 * 2. 转换颜色空间（BGR→RGB）
 * 3. 创建Qt图像对象
 * 4. 初始化蒙版
 * 5. 更新显示
 */
bool ImageCanvas::loadImage(const QString &filePath)
{
    // 使用OpenCV读取图像文件
    originalImage = cv::imread(filePath.toStdString());
    if (originalImage.empty()) {
        qDebug() << "无法加载图像文件:" << filePath;
        return false;
    }

    // 转换颜色空间：OpenCV默认BGR，Qt需要RGB
    cv::cvtColor(originalImage, originalImage, cv::COLOR_BGR2RGB);

    // 创建Qt图像对象，用于显示
    // QImage直接使用OpenCV数据，避免内存拷贝
    originalPixmap = QPixmap::fromImage(QImage(
        originalImage.data,           // 图像数据指针
        originalImage.cols,           // 图像宽度
        originalImage.rows,           // 图像高度
        originalImage.step,           // 每行字节数
        QImage::Format_RGB888         // RGB格式
        ));

    // 初始化蒙版（全黑表示没有修复区域）
    maskImage = cv::Mat::zeros(originalImage.size(), CV_8UC1); // 8位单通道
    maskPixmap = QPixmap(originalPixmap.size());
    maskPixmap.fill(Qt::transparent); // 透明背景

    // 更新缩放图像并重绘
    updateScaledImages();
    update();

    // 发送图像加载成功信号
    emit imageLoaded(true);
    qDebug() << "图像加载成功，尺寸:" << originalImage.cols << "x" << originalImage.rows;
    return true;
}

/**
 * @brief 设置绘制模式
 * @param enabled 是否启用绘制模式
 *
 * 启用时允许用户绘制蒙版，禁用时忽略鼠标事件
 */
void ImageCanvas::setDrawMode(bool enabled)
{
    setMouseTracking(enabled);   // 控制鼠标跟踪
    if (!enabled) {
        isDrawing = false;       // 禁用时停止当前绘制
    }
}

/**
 * @brief 设置当前工具
 * @param tool 工具类型
 *
 * 切换不同的绘制工具，并更新显示状态
 */
void ImageCanvas::setCurrentTool(Tool tool)
{
    currentTool = tool;
    update(); // 刷新显示，更新工具提示
}

/**
 * @brief 绘制事件处理函数
 * @param event 绘制事件
 *
 * 负责在画布上绘制所有内容：
 * - 背景
 * - 缩放后的图像
 * - 蒙版覆盖层
 * - 状态信息
 */
void ImageCanvas::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    // 绘制深灰色背景
    painter.fillRect(rect(), QColor(50, 50, 50));

    if (!displayPixmap.isNull()) {
        // 计算图像在画布中的居中位置
        int x = (width() - displayPixmap.width()) / 2;
        int y = (height() - displayPixmap.height()) / 2;

        // 绘制原始图像
        painter.drawPixmap(x, y, displayPixmap);

        // 绘制蒙版覆盖层（红色半透明）
        if (!maskPixmap.isNull()) {
            // 将蒙版缩放到显示尺寸
            QPixmap scaledMask = maskPixmap.scaled(
                displayPixmap.size(),
                Qt::IgnoreAspectRatio,
                Qt::SmoothTransformation
                );

            // 创建红色半透明覆盖层
            QPixmap redOverlay(scaledMask.size());
            redOverlay.fill(QColor(255, 0, 0, 120)); // 红色，120透明度

            // 使用蒙版作为遮罩，只显示绘制区域
            redOverlay.setMask(scaledMask.createMaskFromColor(Qt::transparent));

            painter.drawPixmap(x, y, redOverlay);
        }

        // 绘制调试和状态信息
        painter.setPen(Qt::white);
        painter.setFont(QFont("Arial", 10));

        // 工具名称转换
        QString toolName;
        switch(currentTool) {
        case Pen: toolName = "画笔"; break;
        case Rectangle: toolName = "矩形"; break;
        case Eraser: toolName = "橡皮擦"; break;
        }

        // 显示当前状态
        painter.drawText(10, 25, QString("缩放: %1x | 工具: %2 | 画笔大小: %3")
                                     .arg(scaleFactor, 0, 'f', 1)
                                     .arg(toolName)
                                     .arg(brushSize));

        // 显示图像信息
        if (!originalImage.empty()) {
            painter.drawText(10, 45, QString("图像: %1 x %2")
                                         .arg(originalImage.cols)
                                         .arg(originalImage.rows));
        }
    } else {
        // 没有图像时的提示信息
        painter.setPen(Qt::white);
        painter.setFont(QFont("Arial", 14));
        painter.drawText(rect(), Qt::AlignCenter, "请通过菜单或工具栏打开图像文件");

        painter.setFont(QFont("Arial", 10));
        painter.drawText(rect().adjusted(0, 40, 0, 0), Qt::AlignCenter,
                         "支持格式: PNG, JPG, BMP, JPEG");
    }
}

/**
 * @brief 鼠标按下事件处理
 * @param event 鼠标事件
 *
 * 开始绘制蒙版：
 * - 检查左键点击
 * - 检查图像是否加载
 * - 记录开始位置
 */
void ImageCanvas::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && !displayPixmap.isNull()) {
        isDrawing = true;                    // 开始绘制
        lastMousePos = event->pos();         // 记录起始位置
        drawOnMask(event->pos());            // 绘制第一个点
    }
}

/**
 * @brief 鼠标移动事件处理
 * @param event 鼠标事件
 *
 * 连续绘制蒙版：
 * - 计算两点间距离
 * - 动态插值确保连续绘制
 * - 性能优化：限制最大步数
 */
void ImageCanvas::mouseMoveEvent(QMouseEvent *event)
{
    if (isDrawing && !displayPixmap.isNull()) {
        QPoint currentPos = event->pos();

        // 计算两点间距离（用于插值密度）
        int dx = currentPos.x() - lastMousePos.x();
        int dy = currentPos.y() - lastMousePos.y();
        int distance = qMax(1, static_cast<int>(qSqrt(dx*dx + dy*dy)));

        // 根据距离动态调整插值步数
        // 确保绘制连续，同时避免性能问题
        int steps = qMin(distance, 50); // 最多50步

        // 在两点间插值绘制
        for (int i = 0; i <= steps; ++i) {
            qreal ratio = static_cast<qreal>(i) / steps;
            int x = lastMousePos.x() + ratio * dx;
            int y = lastMousePos.y() + ratio * dy;
            drawOnMask(QPoint(x, y));  // 在插值点绘制
        }

        lastMousePos = currentPos;  // 更新最后位置
    }
}

/**
 * @brief 鼠标释放事件处理
 * @param event 鼠标事件
 *
 * 结束绘制并通知蒙版更新
 */
void ImageCanvas::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        isDrawing = false;
        // 发送蒙版更新信号，通知算法引擎
        emit maskUpdated(maskImage);
    }
}

/**
 * @brief 在蒙版上绘制
 * @param pos 鼠标在屏幕上的位置
 *
 * 核心绘制逻辑：
 * 1. 坐标转换：屏幕坐标 → 图像坐标
 * 2. 边界检查
 * 3. 根据工具类型绘制
 * 4. 更新双存储（Qt蒙版和OpenCV蒙版）
 */
void ImageCanvas::drawOnMask(const QPoint &pos)
{
    // 安全检查
    if (maskPixmap.isNull() || originalPixmap.isNull()) return;

    // 计算图像在画布中的显示区域
    int displayX = (width() - displayPixmap.width()) / 2;
    int displayY = (height() - displayPixmap.height()) / 2;

    // 检查点击是否在图像范围内
    if (pos.x() < displayX || pos.x() >= displayX + displayPixmap.width() ||
        pos.y() < displayY || pos.y() >= displayY + displayPixmap.height()) {
        return; // 点击在图像外，忽略
    }

    // 坐标转换：屏幕坐标 → 原始图像坐标
    QPointF imagePos = QPointF(
        (pos.x() - displayX) / scaleFactor,  // 考虑显示偏移和缩放
        (pos.y() - displayY) / scaleFactor
        );

    // 确保坐标在图像有效范围内
    imagePos.setX(qMax(0.0, qMin(imagePos.x(), originalPixmap.width() - 1.0)));
    imagePos.setY(qMax(0.0, qMin(imagePos.y(), originalPixmap.height() - 1.0)));

    // 创建Qt绘制器，在蒙版上绘制
    QPainter painter(&maskPixmap);
    painter.setRenderHint(QPainter::Antialiasing); // 抗锯齿

    // 根据工具类型设置绘制属性
    if (currentTool == Eraser) {
        // 橡皮擦模式：清除蒙版
        painter.setCompositionMode(QPainter::CompositionMode_Clear);
        painter.setBrush(Qt::transparent);
        painter.setPen(Qt::NoPen);
    } else {
        // 画笔模式：添加蒙版
        painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
        QColor brushColor(255, 0, 0, 200); // 红色，200透明度
        painter.setBrush(brushColor);
        painter.setPen(Qt::NoPen);
    }

    // 根据工具类型绘制形状
    QPoint center = imagePos.toPoint();
    int radius = brushSize / 2;

    // 确保绘制区域在图像范围内
    QRect circleRect(center.x() - radius, center.y() - radius, brushSize, brushSize);
    circleRect = circleRect.intersected(QRect(0, 0, originalPixmap.width(), originalPixmap.height()));

    if (circleRect.isValid()) {
        // 在Qt蒙版上绘制
        painter.drawEllipse(center, radius, radius);

        // 在OpenCV蒙版上同步绘制
        cv::circle(maskImage,
                   cv::Point(center.x(), center.y()),  // 中心点
                   radius,                             // 半径
                   currentTool == Eraser ? cv::Scalar(0) : cv::Scalar(255), // 颜色：擦除为0，绘制为255
                   -1);                               // 厚度-1表示实心
    }

    update(); // 触发重绘，更新显示
    emit maskUpdated(maskImage); // 通知蒙版更新
}

/**
 * @brief 更新缩放后的图像
 *
 * 根据当前缩放因子重新生成显示图像
 * 使用高质量缩放算法保持图像质量
 */
void ImageCanvas::updateScaledImages()
{
    if (!originalPixmap.isNull()) {
        displayPixmap = originalPixmap.scaled(
            originalPixmap.size() * scaleFactor,  // 目标尺寸
            Qt::KeepAspectRatio,                  // 保持宽高比
            Qt::SmoothTransformation              // 平滑变换
            );
    }
}

// ==================== 缩放操作函数 ====================

/**
 * @brief 放大图像
 * 缩放因子乘以1.2，最大限制在10倍
 */
void ImageCanvas::zoomIn() {
    scaleFactor *= 1.2;
    scaleFactor = qMin(scaleFactor, 10.0); // 限制最大缩放
    updateScaledImages();
    update();
}

/**
 * @brief 缩小图像
 * 缩放因子除以1.2，最小限制在0.1倍
 */
void ImageCanvas::zoomOut() {
    scaleFactor /= 1.2;
    scaleFactor = qMax(scaleFactor, 0.1); // 限制最小缩放
    updateScaledImages();
    update();
}

/**
 * @brief 重置缩放
 * 恢复原始大小显示
 */
void ImageCanvas::resetZoom() {
    scaleFactor = 1.0;
    updateScaledImages();
    update();
}

/**
 * @brief 清除蒙版
 * 重置所有绘制区域，恢复到初始状态
 */
void ImageCanvas::clearMask()
{
    if (!maskImage.empty()) {
        maskImage.setTo(0);                    // OpenCV蒙版清零
        maskPixmap.fill(Qt::transparent);      // Qt蒙版透明
        update();                              // 更新显示
        emit maskUpdated(maskImage);           // 通知更新
        qDebug() << "蒙版已清除";
    }
}

/**
 * @brief 显示修复结果
 * @param result 修复后的图像
 *
 * 将算法修复结果显示在画布上，并清除蒙版
 */
void ImageCanvas::showResult(const cv::Mat &result)
{
    if (result.empty()) {
        qDebug() << "错误: 修复结果为空";
        return;
    }

    // 更新原始图像为修复结果
    originalImage = result.clone();

    // 创建Qt图像对象
    originalPixmap = QPixmap::fromImage(QImage(
        originalImage.data, originalImage.cols, originalImage.rows,
        originalImage.step, QImage::Format_RGB888
        ));

    // 清除蒙版，准备下一次修复
    clearMask();

    // 更新显示
    updateScaledImages();
    update();

    qDebug() << "修复结果显示完成";
}

/**
 * @brief 鼠标滚轮事件处理
 * @param event 滚轮事件
 *
 * 实现图像缩放功能：
 * - 向上滚动：放大
 * - 向下滚动：缩小
 * - 保持鼠标位置的内容不变
 */
void ImageCanvas::wheelEvent(QWheelEvent *event)
{
    if (originalPixmap.isNull()) return;

    // 获取鼠标当前位置（相对窗口坐标）
    QPointF mousePos = event->position();

    // 计算缩放前鼠标位置对应的图像坐标
    QPointF imagePosBeforeZoom;
    if (!displayPixmap.isNull()) {
        int displayX = (width() - displayPixmap.width()) / 2;
        int displayY = (height() - displayPixmap.height()) / 2;

        imagePosBeforeZoom.setX((mousePos.x() - displayX) / scaleFactor);
        imagePosBeforeZoom.setY((mousePos.y() - displayY) / scaleFactor);
    }

    // 计算缩放因子
    double zoomFactor = 1.1;
    if (event->angleDelta().y() > 0) {
        // 向上滚动：放大
        scaleFactor *= zoomFactor;
        scaleFactor = qMin(scaleFactor, 10.0); // 最大放大10倍
    } else {
        // 向下滚动：缩小
        scaleFactor /= zoomFactor;
        scaleFactor = qMax(scaleFactor, 0.1); // 最小缩小到0.1倍
    }

    // 更新缩放后的图像
    updateScaledImages();

    // 理论上应该调整滚动位置以保持鼠标下的内容不变
    // 这里简化实现，只更新缩放

    update();      // 触发重绘
    event->accept(); // 标记事件已处理
}
